home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 3
/
Cream of the Crop 3.iso
/
comm
/
wnos5src.zip
/
PKTDRVR.C
< prev
next >
Wrap
Text File
|
1993-08-09
|
14KB
|
526 lines
/* Driver for FTP Software's packet driver interface. (PC specific code)
* Copyright 1991 Phil Karn, KA9Q
*/
#include <stdio.h>
#include <dos.h>
#include "global.h"
#include "config.h"
#ifdef PACKET
#include "proc.h"
#include "mbuf.h"
#include "netuser.h"
#include "enet.h"
#include "arcnet.h"
#include "ax25.h"
#include "slip.h"
#include "kiss.h"
#include "iface.h"
#include "ec.h"
#include "arp.h"
#include "trace.h"
#include "pktdrvr.h"
#include "devparam.h"
static long near access_type __ARGS((int intno,int if_class,int if_type,
int if_number, char *type,unsigned typelen,
INTERRUPT (*receiver) __ARGS((void)) ));
static int near driver_info __ARGS((int intno,int handle,int *version,
int *class,int *type,int *number,int *basic));
static int near release_type __ARGS((int intno,int handle));
static int near get_address __ARGS((int intno,int handle,char *buf,int len));
static int pk_raw __ARGS((struct iface *iface,struct mbuf *bp));
static int pk_stop __ARGS((struct iface *iface,int tmp));
static int near send_pkt __ARGS((int intno,char *buffer,unsigned length));
#ifdef ARCNET
static char arcip[] = {ARC_IP}, arcarp[] = {ARC_ARP};
#endif
INTERRUPT (*Pkvec[])() = { pkvec0,pkvec1,pkvec2 };
static struct pktdrvr Pktdrvr[PK_MAX];
static int Derr = 0;
static char Pkt_sig[] = "PKT DRVR"; /* Packet driver signature */
#ifdef SLFP
/*
* Send routine for packet driver
*/
int
pk_send(
struct mbuf *bp, /* Buffer to send */
struct iface *iface, /* Pointer to interface control block */
int32 gateway, /* Ignored */
int prec,
int del,
int tput,
int rel)
{
if(iface == NULLIF){
free_p(bp);
return -1;
}
return (*iface->raw)(iface,bp);
}
#endif
/* Send raw packet (caller provides header) */
static int
pk_raw(
struct iface *iface, /* Pointer to interface control block */
struct mbuf *bp) /* Data field */
{
struct mbuf *bp1;
struct pktdrvr *pp = &Pktdrvr[iface->dev];
int16 size = len_p(bp);
/* Perform class-specific processing, if any */
switch(pp->class){
#ifdef ETHER
case CL_ETHERNET:
if(size < RUNT){
/* Pad the packet out to the minimum */
bp1 = alloc_mbuf(RUNT-size);
bp1->cnt = RUNT-size;
append(&bp,bp1);
size = RUNT;
}
break;
#endif
case CL_KISS:
/* This *really* shouldn't be done here, but it was the
* easiest way. Put the type field for KISS TNC on front.
*/
bp1 = pushdown(bp,1);
bp = bp1;
bp->data[0] = PARAM_DATA;
size++;
break;
}
dump(iface,IF_TRACE_OUT,pp->class,bp);
if(bp->next != NULLBUF){
/* Copy to contiguous buffer, since driver can't handle mbufs */
bp1 = copy_p(bp,size);
free_p(bp);
if((bp = bp1) == NULLBUF)
return -1;
}
send_pkt(pp->intno,bp->data,bp->cnt);
free_p(bp);
return 0;
}
/* Packet driver receive routine. Called from an assembler hook that pushes
* the caller's registers on the stack so we can access and modify them.
* This is a rare example of call-by-location in C.
*/
INTERRUPT
pkint(
unsigned short bp,
unsigned short di,
unsigned short si,
unsigned short ds,
unsigned short es,
unsigned short dx,
unsigned short cx,
unsigned short bx,
unsigned short ax,
unsigned short ip,
unsigned short cs,
unsigned short flags,
int dev)
{
struct phdr phdr;
struct pktdrvr *pp = &Pktdrvr[dev];
if(dev < 0 || dev >= PK_MAX || pp->iface == NULLIF)
return; /* Unknown device */
switch(ax){
case 0: /* Space allocate call */
pp->buffer = alloc_mbuf(cx + sizeof(struct phdr));
es = FP_SEG(pp->buffer->data);
di = FP_OFF(pp->buffer->data + sizeof(struct phdr));
pp->buffer->cnt = cx + sizeof(struct phdr);
phdr.iface = pp->iface;
phdr.type = pp->class;
memcpy(&pp->buffer->data[0],(char *)&phdr,sizeof(struct phdr));
break;
case 1: /* Packet complete call */
enqueue(&Hopper,pp->buffer);
pp->buffer = NULLBUF;
default:
break;
}
}
/* Shut down the packet interface */
static int
pk_stop(struct iface *iface,int tmp)
{
struct pktdrvr *pp = &Pktdrvr[iface->dev];
/* Call driver's release_type() entry */
if(release_type(pp->intno,pp->handle1) == -1)
tprintf("%s: release_type error code %u\n",iface->name,Derr);
#if defined(ETHER) || defined (ARCNET)
if(pp->class == CL_ETHERNET || pp->class == CL_ARCNET){
release_type(pp->intno,pp->handle2);
release_type(pp->intno,pp->handle3);
}
#endif
pp->iface = NULLIF;
return 0;
}
/* Attach a packet driver to the system
* argv[0]: hardware type, must be "packet"
* argv[1]: software interrupt vector, e.g., x7e
* argv[2]: interface label, e.g., "trw0"
* argv[3]: buffer size - not used
* argv[4]: maximum transmission unit, bytes, e.g., "1500"
* argv[5]: optional ipaddr
*/
int
pk_attach(int argc,char *argv[],void *p)
{
struct iface *if_pk;
int class, type, i, xdev;
unsigned int intno;
long handle, drvvec;
char iptype[] = {IP_TYPE >> 8,IP_TYPE};
#ifdef ETHER
char tmp[25];
#endif
#ifdef ETHER
char arptype[] = {ARP_TYPE >> 8,ARP_TYPE};
char revarptype[] = {REVARP_TYPE >> 8, REVARP_TYPE};
#endif
char sig[8]; /* Copy of driver signature "PKT DRVR" */
struct pktdrvr *pp;
#ifdef AX25
if(*Mycall == '\0') {
tputs(Nomycall);
return -1;
}
#endif
if(if_lookup(argv[2]) != NULLIF){
tprintf(Ifexist,argv[2]);
return -1;
}
for(i = 0; i < PK_MAX; i++) {
if(Pktdrvr[i].iface == NULLIF)
break;
}
if(i >= PK_MAX){
tprintf("Max %d packet drivers\n",PK_MAX);
return -1;
}
intno = htoi(argv[1]);
/* Verify that there's really a packet driver there, so we don't
* go off into the ozone (if there's any left)
*/
drvvec = (long)getvect(intno);
movblock(FP_OFF(drvvec)+3, FP_SEG(drvvec),
FP_OFF(sig),FP_SEG(sig),strlen(Pkt_sig));
if(strncmp(sig,Pkt_sig,strlen(Pkt_sig)) != 0){
tprintf("No packet driver loaded at int 0x%x\n",intno);
return -1;
}
if_pk = mxallocw(sizeof(struct iface));
if_pk->name = strxdup(argv[2]);
if_pk->addr = Ip_addr;
pp = &Pktdrvr[i];
if_pk->mtu = atoi(argv[4]);
if_pk->dev = i;
if_pk->xdev = 0;
if_pk->raw = pk_raw;
if_pk->stop = pk_stop;
pp->intno = intno;
pp->iface = if_pk;
/* Version 1.08 of the packet driver spec dropped the handle
* requirement from the driver_info call. However, if we are using
* a version 1.05 packet driver, the following call will fail.
*/
if(driver_info(intno,-1,NULL,&class,&type,NULL,NULL) < 0){
/* Find out by exhaustive search what class this driver is (ugh) */
for(class = 1; class <= NCLASS; class++) {
/* Store handle in temp long so we can tell an
* error return (-1) from a handle of 0xffff
*/
handle = access_type(intno,class,ANYTYPE,0,iptype,2,
Pkvec[if_pk->dev]);
if(handle != -1 || Derr == TYPE_INUSE){
pp->handle1 = handle;
break;
}
}
/* Now that we know, release it and do it all over again with the
* right type fields
*/
release_type(intno,pp->handle1);
}
switch(class){
#ifdef ETHER
case CL_ETHERNET:
pp->handle1 = access_type(intno,class,ANYTYPE,0,iptype,2,
Pkvec[if_pk->dev]);
pp->handle2 = access_type(intno,class,ANYTYPE,0,arptype,2,
Pkvec[if_pk->dev]);
pp->handle3 = access_type(intno,class,ANYTYPE,0,revarptype,2,
Pkvec[if_pk->dev]);
setencap(if_pk,"Ethernet");
/* Get hardware Ethernet address from driver */
if_pk->hwaddr = mxallocw(EADDR_LEN);
get_address(intno,pp->handle1,if_pk->hwaddr,EADDR_LEN);
if(if_pk->hwaddr[0] & 1){
tprintf("Warning! Iface '%s' has a multicast address:",
if_pk->name);
tprintf(" (%s)\n",
(*if_pk->iftype->format)(tmp,if_pk->hwaddr));
}
break;
#endif
#ifdef ARCNET
case CL_ARCNET:
pp->handle1 = access_type(intno,class,ANYTYPE,0,arcip,1,
Pkvec[if_pk->dev]);
pp->handle2 = access_type(intno,class,ANYTYPE,0,arcarp,1,
Pkvec[if_pk->dev]);
if_pk->send = anet_send;
if_pk->output = anet_output;
/* Get hardware ARCnet address from driver */
if_pk->hwaddr = mxallocw(AADDR_LEN);
get_address(intno,pp->handle1,if_pk->hwaddr,AADDR_LEN);
break;
#endif
case CL_SERIAL_LINE:
pp->handle1 = access_type(intno,class,ANYTYPE,0,NULLCHAR,0,
Pkvec[if_pk->dev]);
setencap(if_pk,"SLIP");
break;
#ifdef AX25
case CL_KISS: /* Note that the raw routine puts on the command */
case CL_AX25:
for(xdev = 0; xdev < SLIP_MAX; xdev++) {
if(Slip[xdev].iface == NULLIF)
break;
}
if(xdev >= SLIP_MAX) {
tprintf("Max %d slip/asy/nrs devices\n",SLIP_MAX);
return -1;
}
Slip[xdev].iface = if_pk;
Slip[xdev].kiss[if_pk->port] = if_pk; /* G1EMM */
pp->handle1 = access_type(intno,class,ANYTYPE,0,NULLCHAR,0,
Pkvec[if_pk->dev]);
setencap(if_pk,"AX25");
if_pk->hwaddr = strxdup(Mycall);
init_maxheard(if_pk);
init_flags(if_pk);
break;
#endif
#ifdef SLFP
case CL_SLFP:
pp->handle1 = access_type(intno,class,ANYTYPE,0,NULLCHAR,0,
Pkvec[if_pk->dev]);
if_pk->send = pk_send;
setencap(if_pk,"SLFP");
get_address(intno,pp->handle1,(char *)&if_pk->addr,4);
break;
#endif
default:
tprintf("Packet driver has unsupported class %u\n",class);
xfree(if_pk->name);
xfree(if_pk);
return -1;
}
pp->class = class;
if_pk->next = Ifaces;
Ifaces = if_pk;
if_pk->niface = Niface++;
return 0;
}
static long near
access_type(int intno,int if_class,int if_type,int if_number,char *type,unsigned typelen,INTERRUPT (*receiver)())
{
union REGS regs;
struct SREGS sregs;
segread(&sregs);
regs.h.dl = if_number; /* Number */
sregs.ds = FP_SEG(type); /* Packet type template */
regs.x.si = FP_OFF(type);
regs.x.cx = typelen; /* Length of type */
sregs.es = FP_SEG(receiver); /* Address of receive handler */
regs.x.di = FP_OFF(receiver);
regs.x.bx = if_type; /* Type */
regs.h.ah = ACCESS_TYPE; /* Access_type() function */
regs.h.al = if_class; /* Class */
int86x(intno,®s,®s,&sregs);
if(regs.x.cflag) {
Derr = regs.h.dh;
return -1;
}
return regs.x.ax;
}
static int near
release_type(int intno,int handle)
{
union REGS regs;
regs.x.bx = handle;
regs.h.ah = RELEASE_TYPE;
int86(intno,®s,®s);
if(regs.x.cflag){
Derr = regs.h.dh;
return -1;
}
return 0;
}
static int near
send_pkt(int intno,char *buffer,unsigned length)
{
union REGS regs;
struct SREGS sregs;
segread(&sregs);
sregs.ds = FP_SEG(buffer);
sregs.es = FP_SEG(buffer); /* for buggy univation pkt driver - CDY */
regs.x.si = FP_OFF(buffer);
regs.x.cx = length;
regs.h.ah = SEND_PKT;
int86x(intno,®s,®s,&sregs);
if(regs.x.cflag){
Derr = regs.h.dh;
return -1;
}
return 0;
}
static int near
driver_info(int intno,int handle,int *version,int *class,int *type,int *number,int *basic)
{
union REGS regs;
regs.x.bx = handle;
regs.h.ah = DRIVER_INFO;
regs.h.al = 0xff;
int86(intno,®s,®s);
if(regs.x.cflag){
Derr = regs.h.dh;
return -1;
}
if(version != NULL)
*version = regs.x.bx;
if(class != NULL)
*class = regs.h.ch;
if(type != NULL)
*type = regs.x.dx;
if(number != NULL)
*number = regs.h.cl;
if(basic != NULL)
*basic = regs.h.al;
return 0;
}
static int near
get_address(int intno,int handle,char *buf,int len)
{
union REGS regs;
struct SREGS sregs;
segread(&sregs);
sregs.es = FP_SEG(buf);
regs.x.di = FP_OFF(buf);
regs.x.cx = len;
regs.x.bx = handle;
regs.h.ah = GET_ADDRESS;
int86x(intno,®s,®s,&sregs);
if(regs.x.cflag){
Derr = regs.h.dh;
return -1;
}
return 0;
}
/*----------------------------------------------------------------------*
*-----------------------------------------------------------------------*/
void pkt_suspend(void)
{
struct pktdrvr *pp;
int i;
for(i=0;i < PK_MAX;i++){ /* scan the asy structures */
pp = &Pktdrvr[i];
if(pp->iface == NULLIF)
continue;
release_type(pp->intno,pp->handle1);
if(pp->class == CL_ETHERNET || pp->class == CL_ARCNET){
release_type(pp->intno,pp->handle2);
release_type(pp->intno,pp->handle3);
}
}
}
/*----------------------------------------------------------------------*
*-----------------------------------------------------------------------*/
void pkt_restore(void)
{
struct pktdrvr *pp;
int i;
for(i = 0; i < PK_MAX; i++) {
pp = &Pktdrvr[i];
if(pp->iface == NULLIF)
continue;
switch (pp->class) {
#ifdef XXX
case CL_ETHERNET:
pp->handle1 = access_type(pp->intno,pp->class,ANYTYPE,0,iptype,2, Pkvec[i]);
pp->handle2 = access_type(pp->intno,pp->class,ANYTYPE,0,arptype,2, Pkvec[i]);
pp->handle3 = access_type(pp->intno,pp->class,ANYTYPE,0,revarptype,2, Pkvec[i]);
break;
#endif
#ifdef ARCNET
case CL_ARCNET:
pp->handle1 = access_type(pp->intno,pp->class,ANYTYPE,0,arcip,1, Pkvec[i]);
pp->handle2 = access_type(pp->intno,pp->class,ANYTYPE,0,arcarp,1, Pkvec[i]);
break;
#endif
case CL_SERIAL_LINE:
pp->handle1 = access_type(pp->intno,pp->class,ANYTYPE,0,NULLCHAR,0, Pkvec[i]);
break;
#ifdef AX25
case CL_KISS: /* Note that the raw routine puts on the command*/
case CL_AX25:
pp->handle1 = access_type(pp->intno,pp->class,ANYTYPE,0,NULLCHAR,0, Pkvec[i]);
break;
#endif
#ifdef SLFP
case CL_SLFP:
pp->handle1 = access_type(pp->intno,pp->class,ANYTYPE,0,NULLCHAR,0, Pkvec[i]);
break;
#endif
}
}
}
#endif PACKET